import { FC, useEffect, useState } from "react";
import { observer, inject } from "mobx-react";
import { useParams, useNavigate } from "react-router-dom";
import {
  Layout,
  Divider,
  Space,
  Row,
  Col,
  Button,
  Modal,
  Form,
  Select,
  InputNumber,
  Radio,
  Popover,
  Table,
  Dropdown,
  message,
  Popconfirm,
  Tooltip,
  Upload,
} from "antd";

import _ from "lodash";
import {
  DownloadOutlined,
  DeleteOutlined,
  TableOutlined,
} from "@ant-design/icons";
import * as XLSX from "xlsx";
import { RcFile } from "rc-upload/lib/interface";
import { transformArray } from "../../utils";

import {
  createReactorExcelData,
  parseExcelData,
  replaceReagentIds,
  getFileNameWithoutExtension,
} from "../../utils/exportDesigner";
import SelectReactorPlateModal from "./SelectReactorPlateModal";
import ReactionExcelDesigner from "./ReactionExcelDesigner";

import StepTop from "./StepTop";

// import ReacterPlateCanvas from "./ReacterPlateCanvas";

import { ITStore } from "../../store";

import { ITReagent } from "../../store/interfaces";

interface TProp {
  store: ITStore;
  reSelectReactorPlateModal: (data: boolean) => void;
}

const { Content } = Layout;

/**
 * 固体不能选体积
 * 固体没有分子量不能选择mmol
 *
 * 液体选择质量需要密度
 * 液体选择mmol需要密度和分子量
 */
const EditReactorModal: FC<TProp | any> = inject("store")(
  observer(({ store }: TProp) => {
    const {
      languageStore: { lang },
      designerStore: {
        showReactorReagentDataModal,
        editReactorReagentData,
        changeShowReactorReagentDataModal,
        changeEditReactorReagentData,
        changeReactionDrawerData,
        updateReactDesigner,
        getReactDesignById,
      },
      reagentStore: { getReagentInfoById },
    } = store;
    const [form] = Form.useForm();
    const [reagentName, setReagentName] = useState("");
    const [currentSlot, setCurrentSlot] = useState();

    const [radioOptions, setRadioOptions] = useState<any>([]);

    // 是否显示温度表单
    const [showTempForm, setShowTempForm] = useState(false);

    const [loading, setloading] = useState(false);
    // const [slotOptions, setSlotOptions] = useState<SelectProps["options"]>([]);

    const closeModal = () => {
      changeShowReactorReagentDataModal(false);
      changeEditReactorReagentData(null);
      form.resetFields();
    };

    useEffect(() => {
      const list = ["mg", "ml", "mmol"];
      let options: any = [];
      if (editReactorReagentData) {
        const { reagentInfo: reagentId } = editReactorReagentData as any;
        const regInfo: ITReagent | null = getReagentInfoById(reagentId);
        const { type, mw, density } = regInfo || {};
        if (type === "powder") {
          options.push({
            label: lang["langmg"],
            value: "mg",
          });
          if (mw) {
            options.push({
              label: lang["langmmol"],
              value: "mmol",
            });
          }
        } else {
          options.push({
            label: lang["langmlunit"],
            value: "ml",
          });
          if (density) {
            options.push({
              label: lang["langmg"],
              value: "mg",
            });
            if (mw) {
              options.push({
                label: lang["langmmol"],
                value: "mmol",
              });
            }
          }
        }
      } else {
        list.forEach((item) => {
          if (item === "mg") {
            options.push({
              label: lang["langmg"],
              value: item,
            });
          } else if (item === "ml") {
            options.push({
              label: lang["langmlunit"],
              value: item,
            });
          } else if (item === "mmol") {
            options.push({
              label: lang["langmmol"],
              value: item,
            });
          }
        });
      }
      setRadioOptions(options);
    }, [lang, editReactorReagentData]);

    useEffect(() => {
      if (editReactorReagentData) {
        const {
          reagentInfo,
          data: { slotName, reagent },
          reactData,
          reagentIndex,
        }: any = editReactorReagentData;
        let temp = false;
        if (reagentInfo === "Temp/Time") {
          temp = true;
          setReagentName(lang["langreactiontime"]);
        }

        setShowTempForm(temp);
        setCurrentSlot(slotName || "");
        let hasData = false;

        const { slotreagent, plate } = reactData;
        if (slotreagent) {
          const plateInfo = slotreagent[plate];
          const slotInfo = plateInfo[slotName];
          if (slotInfo) {
            const reagentAmn = slotInfo[reagentIndex];
            if (reagentAmn) {
              if (!temp) {
                const { amount, unit } = reagentAmn;
                form.setFieldsValue({
                  amount,
                  unit,
                });
              } else {
                const { templature, time } = reagentAmn;
                form.setFieldsValue({
                  templature,
                  time,
                });
              }
              hasData = true;
            }
          }
        }
        if (!hasData) {
          const regInfo: ITReagent | null = getReagentInfoById(reagentInfo);
          if (regInfo) {
            const { type, name } = regInfo;
            setReagentName(name || "");
            let unit = "ml";
            if (type === "powder") {
              unit = "mg";
            }
            form.setFieldValue("unit", unit);
          }
        }
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [editReactorReagentData]);

    const onFinish = async (data: any) => {
      const {
        data: { plateName, slotName },
        reagentInfo,
        reactData,
        reagentIndex,
      } = editReactorReagentData as any;
      const { slotreagent, _id } = reactData;

      try {
        setloading(true);

        // 公共处理逻辑
        const createSlotReagent = (updateFields: Record<string, any>) => {
          const tempSlotReagent = slotreagent ? _.cloneDeep(slotreagent) : {};

          // 初始化嵌套结构
          _.set(tempSlotReagent, [plateName, slotName, reagentIndex], {
            ...(tempSlotReagent[plateName]?.[slotName]?.[reagentIndex] || {}),
            ...updateFields,
          });

          return tempSlotReagent;
        };

        // 根据条件选择要更新的字段
        const updateFields = showTempForm
          ? { templature: data.templature, time: data.time }
          : {
              reagentid: reagentInfo,
              amount: data.amount,
              unit: data.unit,
            };

        // 创建更新后的试剂数据
        const newSlotreagent = createSlotReagent(updateFields);

        // 统一请求处理
        const res = await updateReactDesigner({
          id: _id,
          slotreagent: newSlotreagent,
        });
        if (!res) {
          const result = await getReactDesignById({ id: _id });
          if (result) {
            changeReactionDrawerData(result);
          }
        } else {
          message.error("添加失败, 请稍后再试!");
        }
      } catch (error) {
        message.error("操作过程中发生错误");
      } finally {
        setloading(false);
        closeModal();
      }
    };

    return (
      <Modal
        title={
          showTempForm
            ? reagentName
            : `${currentSlot}添加试剂(${reagentName})数量`
        }
        open={showReactorReagentDataModal}
        onOk={() => {
          form.submit();
        }}
        onCancel={closeModal}
        destroyOnClose={true}
        width={720}
        confirmLoading={loading}
      >
        {showTempForm && (
          <Form
            name="reaginetForm"
            form={form}
            labelCol={{ span: 6 }}
            wrapperCol={{ span: 18 }}
            onFinish={onFinish}
          >
            <Form.Item
              label={lang["langreactiontpure"]}
              name="templature"
              rules={[{ required: true }]}
            >
              <InputNumber
                style={{ width: "100%" }}
                addonAfter={lang["langtemperatureoc"]}
              />
            </Form.Item>
            <Form.Item
              label={lang["langreacttime"]}
              name="time"
              rules={[{ required: true }]}
            >
              <InputNumber
                style={{ width: "100%" }}
                addonAfter={lang["langtimehours"]}
              />
            </Form.Item>
          </Form>
        )}
        {!showTempForm && (
          <Form
            name="reaginetForm"
            form={form}
            labelCol={{ span: 6 }}
            wrapperCol={{ span: 18 }}
            onFinish={onFinish}
          >
            <Form.Item
              label={lang["langamount"]}
              name="amount"
              rules={[{ required: true }]}
            >
              <InputNumber style={{ width: "100%" }} />
            </Form.Item>
            <Form.Item name="unit" label="Unit" rules={[{ required: true }]}>
              <Radio.Group options={radioOptions} />
            </Form.Item>
          </Form>
        )}
      </Modal>
    );
  })
);

const ReactionsTable: FC<any> = inject("store")(
  observer(({ store }: TProp) => {
    const {
      languageStore: { lang },
      designerStore: {
        currentDesigner,
        getReactDesignerList,
        changeOpenReactionDrawer,
        changeReactionDrawerData,
        reactionDesignerList,
        delReactDesigner,
        createReactorExcel,
      },
      shelfStore: { allShelf },
      reagentStore: { getReagentInfoById, allReagent },
    } = store;

    const [loading, setLoading] = useState(false);

    const getData = async () => {
      await getReactDesignerList({
        designer: currentDesigner?.id,
      });
    };

    const delClick = async (record: any) => {
      await delReactDesigner({ id: record._id });
      message.success(lang["langdeletesuccess"]);
      getData();
    };

    const downReactionExcel = async (record: any) => {
      if (currentDesigner && allShelf.length && allReagent.length) {
        setLoading(true);
        const { slotShelf, reactorSlotShelf, name } = currentDesigner;
        const { reagentsort, slotreagent, plate } = record;

        let shelfName = slotShelf[plate].shelf;
        const shelfInfo = allShelf.find((item) => item.name === shelfName);
        const bottleList = shelfInfo?.bottleList || [];
        const bottleNames: string[] = [];
        if (bottleList.length > 0) {
          bottleList.forEach((item) => {
            bottleNames.push(item.name);
          });
        }
        const newbottleNames: any = transformArray(bottleNames);

        const { excelHeader, excelData } = createReactorExcelData({
          reagentsort,
          slotreagent,
          getReagentInfoById,
          plate,
          bottleNames: newbottleNames,
          shelfName
        });

        await createReactorExcel({
          name: `${name}_${record.name}`,
          excelHeader,
          excelData,
        });
        setLoading(false);
      }
    };

    useEffect(() => {
      if (currentDesigner) {
        getData();
      }
    }, [currentDesigner]);

    const columns: any = [
      {
        title: lang["langreactionname"],
        dataIndex: "name",
        key: "name",
      },
      {
        title: lang["langreactionslotposition"],
        dataIndex: "plate",
        key: "plate",
      },
      {
        title: lang["langedit"],
        dataIndex: "reagent",
        key: "reagent",
        width: 100,
        align: "center",
        render: (text: string, record: any) => {
          return (
            <Space>
              <Tooltip title={lang["langdownloadreactionexcel"]} placement="topRight">
                <Button
                  type="link"
                  icon={<DownloadOutlined />}
                  onClick={() => {
                    downReactionExcel(record);
                  }}
                />
              </Tooltip>
              <Tooltip title={lang["langeditreactionexcel"]} placement="topRight">
                <Button
                  type="link"
                  icon={<TableOutlined />}
                  onClick={() => {
                    changeReactionDrawerData(record);
                    changeOpenReactionDrawer(true);
                  }}
                />
              </Tooltip>
              <Popconfirm
                placement="top"
                title={lang["langconfirmdel"]}
                onConfirm={() => {
                  delClick(record);
                }}
              >
                <Tooltip title={lang["langdelete"]}>
                  <Button type="link" danger icon={<DeleteOutlined />} />
                </Tooltip>
              </Popconfirm>
            </Space>
          );
        },
      },
    ];

    return (
      <Table
        dataSource={reactionDesignerList}
        columns={columns}
        bordered
        loading={loading}
      />
    );
  })
);

/**
 * DesignerReactor 组件是一个函数组件，用于展示设计师界面中的反应盘。
 *
 * @param store 包含多个子存储（languageStore, designerStore, shelfStore, reagentStore）的对象，提供所需的状态和方法。
 * @returns 返回JSX.Element类型的React元素。
 */
const DesignerReactor: FC<TProp | any> = ({ store }: TProp): JSX.Element => {
  const {
    languageStore: { lang },
    designerStore: {
      currentDesigner,
      getDesignerInfo,
      updateDesigner,
      createReactDesigner,
      getReactDesignerList,
    },
    shelfStore: { getAllShelf, allShelf },
    bottleStore: { getAllBottle, allBottle },
    reagentStore: { getAllReagetList, allReagent },
    dictionaryStore: { fullDicts, getFullDict },
  } = store;

  const params = useParams();
  const navigate = useNavigate();

  // 选择反应盘弹窗的显示状态
  const [showReactorPlateModal, setShowReactorPlateModal] = useState(false);

  // 反应盘的信息
  const [reactorPlateName, setReactorPlateName] = useState<string>("");

  // 关闭反应盘弹窗
  const closeReactorPlateModal = () => {
    setShowReactorPlateModal(false);
  };

  const clickPrev = () => {
    navigate(`/designer/reagents/${params.id}`);
  };

  const clickNext = async () => {
    const { id } = currentDesigner || {};
    await updateDesigner({
      id,
      step: 4,
    });
    navigate(`/designer/finished/${params.id}`);
  };

  useEffect(() => {
    if (!allReagent.length) {
      getAllReagetList();
    }
    if (!allBottle.length) {
      getAllBottle();
    }
    if (!allShelf.length) {
      getAllShelf();
    }
    if (!fullDicts || !fullDicts.length) {
      getFullDict(false);
    }
  }, []);

  useEffect(() => {
    if (!currentDesigner) {
      const { id } = params;
      if (id) {
        getDesignerInfo({ id });
      }
    } else if (currentDesigner) {
      const { reactors } = currentDesigner;
      if (reactors) {
        const { plateName } = reactors;
        setReactorPlateName(plateName);
      }
    }
  }, [currentDesigner, params]);

  const createReactDesignerByExcel = async (data: any) => {
    const designerId = currentDesigner?.id;
    await createReactDesigner({
      ...data,
      designer: designerId,
    });

    getReactDesignerList({
      designer: designerId,
    });
  };

  /**
   * 检查反应盘是否正确。
   */
  const checkPlane = (list: any) => {
    const { slotShelf, reagents } = currentDesigner || {};
    const reagentKeys: string[] = [];
    const tempReagentKeys = Object.keys(reagents || {});
    tempReagentKeys.forEach((key: string) => {
      const value = (reagents || {})[key];
      const slotKeys = Object.keys(value || {});
      if (slotKeys.length) {
        reagentKeys.push(key);
      }
    });

    const planes: string[] = [];
    Object.keys(slotShelf).forEach((key: string) => {
      const slotValue = slotShelf[key];
      allShelf.some((sitem: any) => {
        if (
          sitem.name === slotValue.shelf &&
          (sitem.rackType === "reagent" || sitem.rackType === "reactor")
        ) {
          if (reagentKeys.indexOf(key) < 0) {
            planes.push(key);
            return true;
          }
        }
        return false;
      });
    });

    if (planes.length) {
      const listKey = Object.keys(list)[0];
      if (planes.indexOf(listKey) > -1) {
        return true;
      }
    }

    return false;
  };

  const upprops = {
    maxCount: 1,
    accept: ".xlsx",
    // action: "/api/designer/import",
    showUploadList: false,
    beforeUpload: (file: RcFile) => {

      const reader = new FileReader();
      reader.readAsArrayBuffer(file);
      reader.onload = (event: any) => {
        const { result } = event.target;
        const workbook = XLSX.read(result, { type: "buffer" });

        const xlsx_data = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], {
            header: 1,          // 保留行号
            raw: false,          // 关键参数：禁用自动类型转换
            defval: "",          // 空单元格默认值
            blankrows: true      // 保留空行
          });


        // const sheetValues = Object.values(workbook.Sheets);
        const parseData = parseExcelData(xlsx_data);
        const { names, list } = parseData;

        const plate = Object.keys(list)[0];
        if (!checkPlane(list)) {
          message.error(`反应盘${plate}无效`);
          return;
        }

        if (names.length) {
          // 无效试剂
          const invalidNames = new Set();
          const reagents: any[] = [];
          names.forEach((name: string) => {
            if (name !== "Temp/Time") {
              let findItem: any = null;
              allReagent.some((item: ITReagent) => {
                if (
                  item.name === name ||
                  item.abbreviation === name ||
                  item.cnname === name
                ) {
                  findItem = item;
                  return true;
                }
                return false;
              });
              if (findItem) {
                reagents.push({
                  name,
                  id: findItem.id,
                });
              } else {
                if (name !== "Reactor" && name !== "Slot") {
                  invalidNames.add(name);
                }
              }
            }
          });

          if (invalidNames.size) {
            message.error(
              `无效的试剂名称: ${Array.from(invalidNames).join(", ")}`
            );
          } else {
            const reagentIdList = replaceReagentIds(list, reagents);
            const reagentsort: any = [];
            names.forEach((name: string) => {
              if (name !== "Reactor" && name !== "Slot") {
                if (name !== "Temp/Time") {
                  reagentsort.push(
                    reagents.find((item: any) => item.name === name).id
                  );
                } else {
                  reagentsort.push(name);
                }
              }
            });
            createReactDesignerByExcel({
              name: getFileNameWithoutExtension(file.name),
              plate,
              reagentsort,
              slotreagent: reagentIdList,
            });
          }
        }
      };
      return false;
    },
  };

  return (
    <Content className="mainLayout">
      {/* 步骤 */}
      <StepTop currentStep={3} />
      <Divider />
      <Row style={{ marginBottom: 20 }}>
        <Col span={24}>
          <Space wrap style={{ float: "right" }}>
            <Button
              type="primary"
              onClick={() => {
                setShowReactorPlateModal(true);
              }}
            >
              {lang["langaddnewreactionexcel"]}
            </Button>

            <Upload {...upprops}>
              <Button>{lang["langimportreactiondesigner"]}</Button>
            </Upload>
          </Space>
        </Col>
      </Row>
      <ReactionsTable />
      <Row>
        <Col span={24} style={{ textAlign: "center", marginTop: 20 }}>
          <Space>
            <Button onClick={clickPrev}>{lang["langprev"]}</Button>
            <Button type="primary" onClick={clickNext}>
              {lang["langnext"]}
            </Button>
          </Space>
        </Col>
      </Row>

      {/* 编辑反应试剂弹窗 */}
      <EditReactorModal />

      {/* 设置温度和反应时间弹窗 */}
      {/* <TemplateTimeModal showTimeModal={showTimeModal} close={closeTimeModal} /> */}

      {/* 添加反应盘弹窗 */}
      <SelectReactorPlateModal
        isShow={showReactorPlateModal}
        close={closeReactorPlateModal}
      />
      <ReactionExcelDesigner />
    </Content>
  );
};

export default inject("store")(observer(DesignerReactor));
